Data Source

  • These data come from the FCC’s Form 477 Fixed Broadband Deployment Data.
  • FCC data is released biannually on a year and half delay from when it was collected. New data can be downloaded from this link.
  • Data presented here are from June of 2020.

Data specifics

  • All internet providers must submit form 477 to the FCC biannually detailing the Maximum download and upload speeds (Mbps) they advertise to consumers along with other information about the company.
  • The FCC makes these data publicly available on a year and a half delay from when all 477 forms are submitted.
    • Limitations: (1) The data are available at the census block level, but are likely to overstate coverage; if an internet provider provides internet to a single person in a census block, the entire census block is marked as having coverage by that provider.
    • Strengths: (1) These are the same data used by the government to make policy decisions regarding broadband access. (2) The Broadband Deployment Accuracy and Technological Availability (DATA) Act of March 2020 is intended to reduce the limitation listed above.
  • The FCC has established benchmarks for “advanced telecommunications capability”, services that enables “users to originate and receive high-quality voice, data, graphics, and video telecommunications.” The current benchmarks are set at speeds of 25 (download) and 3 (upload) Mbps (2020 Broadband Deployment Report).

Variable descriptions

Variables include:

# meta %>% 
#   filter(su_blkgp == 1) %>%
#   select(varname, about) %>% as.list()

glimpse(eastblkgps)
## Rows: 46
## Columns: 11
## $ Blkgr        <chr> "510010901001", "510010901002", "510010901003", "51001090…
## $ tract        <dbl> 51001090100, 51001090100, 51001090100, 51001090100, 51001…
## $ resproviders <int> 9, 8, 8, 9, 9, 9, 9, 7, 8, 7, 8, 8, 8, 8, 8, 9, 8, 3, 8, …
## $ bb253_num    <int> 6, 5, 5, 6, 6, 6, 6, 4, 6, 5, 6, 6, 6, 6, 6, 6, 6, 2, 6, …
## $ bb253_per    <dbl> 66.7, 62.5, 62.5, 66.7, 66.7, 66.7, 66.7, 57.1, 75.0, 71.…
## $ bbmin_dl     <dbl> 2.0, 2.0, 2.0, 2.0, 1.5, 2.0, 1.5, 2.0, 1.5, 2.0, 1.5, 2.…
## $ bbmax_dl     <int> 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 200…
## $ bbmin_up     <dbl> 0.768, 0.768, 0.768, 0.768, 0.384, 0.768, 0.384, 0.768, 0…
## $ bbmax_up     <int> 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 2000, 200…
## $ avgMaxAdDown <dbl> 262.05535, 366.43713, 363.01818, 333.31591, 165.62523, 30…
## $ avgMaxAdUp   <dbl> 114.636745, 228.947713, 190.067618, 163.903828, 105.02847…
  • BlockCode: geographic identifer for spatial area (tracts, block groups, and blocks)

  • Blkgr: geographic identifer for spatial area (tracts, block groups, and blocks)

  • tract: geographic identifer for spatial area (tracts, block groups, and blocks)

  • resproviders: The number of residential internet providers in the block/block group/tract

  • bb253_num: The number of residential broadband providers providing service that meets the FCC benchmark for “advanced telecommunications capability”, 25/3 Mbps

  • bb253_per: The percent of residential broadband providers providing service that meets the FCC benchmark for “advanced telecommunications capability”, 25/3 Mbps

  • bbmin_dl: The minimum advertised download speed provider in the block/block group/tract

  • bbmax_dl: The maximum advertised download speed provider in the block/block group/tract

  • bbmin_up: The minimum advertised upload speed provider in the block/block group/tract

  • bbmax_up: The maximum advertised upload speed provider in the block/block group/tract

  • avgMaxAdDown:The average maximum advertised download speed by each broadband provider in the block/block group/tract

  • avgMaxAdUp: The average maximum advertised upload speed by each broadband provider in the block/block group/tract

5-number summaries of variables by block groups:

eastblkgps %>% select(-c(Blkgr, tract)) %>% 
  select(where(~is.numeric(.x))) %>% 
  as.data.frame() %>% 
  stargazer(., type = "text", title = "Summary Statistics", digits = 1,
            summary.stat = c("mean", "sd", "min", "median", "max"))
## 
## Summary Statistics
## ===============================================
## Statistic     Mean   St. Dev. Min  Median  Max 
## -----------------------------------------------
## resproviders   7.7     1.8     1     8      9  
## bb253_num      5.5     1.2     1     6      7  
## bb253_per     73.0     8.8    57.1  75.0  100.0
## bbmin_dl       5.1     15.7    1    1.5    100 
## bbmax_dl     1,876.1  474.3   100  2,000  2,000
## bbmin_up       0.7     0.7    0.1   0.4    3.0 
## bbmax_up     1,870.8  494.6    3   2,000  2,000
## avgMaxAdDown  316.4    96.6   54.3 334.6  451.2
## avgMaxAdUp    203.8    75.8   2.6  225.5  336.0
## -----------------------------------------------

Visual distribution

Tracts

easttracts %>% 
  pivot_longer(-tract, names_to = "measure", values_to = "value") %>%
  mutate(measure = factor(measure, levels = c("resproviders", "bb253_num", "bb253_per",
                                              "avgMaxAdDown", "avgMaxAdUp",
                                              "bbmax_dl", "bbmax_up", "bbmin_dl", "bbmin_up"))) %>% 
  ggplot(aes(x = value, fill = measure)) +
  scale_fill_viridis(option = "plasma", discrete = TRUE, guide = "none") +
  geom_histogram() + 
  facet_wrap(~measure, scales = "free")

Block groups

eastblkgps %>% select(-tract) %>% 
  pivot_longer(-Blkgr, names_to = "measure", values_to = "value") %>%
  mutate(measure = factor(measure, levels = c("resproviders", "bb253_num", "bb253_per",
                                              "avgMaxAdDown", "avgMaxAdUp",
                                              "bbmax_dl", "bbmax_up", "bbmin_dl", "bbmin_up"))) %>% 
  ggplot(aes(x = value, fill = measure)) +
  scale_fill_viridis(option = "plasma", discrete = TRUE, guide = "none") +
  geom_histogram() + 
  facet_wrap(~measure, scales = "free")

Blocks

eastblocks %>% select(-tract, Blkgr) %>% 
  pivot_longer(-BlockCode, names_to = "measure", values_to = "value") %>%
  mutate(measure = factor(measure, levels = c("resproviders", "bb253_num", "bb253_per",
                                              "avgMaxAdDown", "avgMaxAdUp",
                                              "bbmax_dl", "bbmax_up", "bbmin_dl", "bbmin_up"))) %>% 
  ggplot(aes(x = value, fill = measure)) +
  scale_fill_viridis(option = "plasma", discrete = TRUE, guide = "none") +
  geom_histogram() + 
  facet_wrap(~measure, scales = "free")

Mapping the data

Number of residential broadband providers

Tracts

pal <- colorNumeric("plasma", reverse = TRUE, domain = maptracts$resproviders)

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = maptracts,
              fillColor = ~pal(resproviders),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", maptracts$GEOID, "<br>",
                             "Number of residential providers: ", maptracts$resproviders)
  ) %>% 
  addLegend("bottomright", pal = pal, values = maptracts$resproviders, 
            title = "Number of residential <br> providers", opacity = 0.7)

Block groups

pal <- colorNumeric("plasma", reverse = TRUE, domain = mapblkgps$resproviders)

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = mapblkgps,
              fillColor = ~pal(resproviders),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", mapblkgps$GEOID, "<br>",
                             "Number of residential providers: ", mapblkgps$resproviders)
  ) %>% 
  addLegend("bottomright", pal = pal, values = mapblkgps$resproviders, 
            title = "Number of residential <br> providers", opacity = 0.7)

Blocks

Block level maps are slow to render and may be added later.

Average maximum advertised download speeds

Tracts

pal <- colorNumeric("plasma", reverse = TRUE, domain = maptracts$avgMaxAdDown) 

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = maptracts,
              fillColor = ~pal(avgMaxAdDown),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", maptracts$GEOID, "<br>",
                             "Average max advertised <br> download speeds: ", round(maptracts$avgMaxAdDown, 2))
  ) %>% 
  addLegend("bottomright", pal = pal, values = maptracts$avgMaxAdDown, 
            title = "Average maximum <br>advertised  <br>download speeds", opacity = 0.7)

Block groups

pal <- colorNumeric("plasma", reverse = TRUE, domain = mapblkgps$avgMaxAdDown) 

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = mapblkgps,
              fillColor = ~pal(avgMaxAdDown),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", mapblkgps$GEOID, "<br>",
                             "Average max advertised <br> download speeds: ", round(mapblkgps$avgMaxAdDown, 2))
  ) %>% 
  addLegend("bottomright", pal = pal, values = mapblkgps$avgMaxAdDown, 
            title = "Average maximum <br>advertised  <br>download speeds", opacity = 0.7)

Blocks

Block level maps are slow to render and may be added later.

Maximum available advertised download speeds

Tracts

pal <- colorNumeric("plasma", reverse = TRUE, domain = maptracts$bbmax_dl)

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = maptracts,
              fillColor = ~pal(bbmax_dl),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", maptracts$GEOID, "<br>",
                             "Max available <br> advertised download speeds: ", round(maptracts$bbmax_dl, 2))
  ) %>% 
  addLegend("bottomright", pal = pal, values = maptracts$bbmax_dl, 
            title = "Max available <br>advertised <br> download speeds", opacity = 0.7)

Block groups

pal <- colorNumeric("plasma", reverse = TRUE, domain = mapblkgps$bbmax_dl)

leaflet() %>% 
  addProviderTiles("CartoDB.Positron") %>% 
  addPolygons(data = mapblkgps,
              fillColor = ~pal(bbmax_dl),
              weight = 1,
              opacity = 1,
              color = "white", 
              fillOpacity = 0.6,
              highlight = highlightOptions(
                weight = 2,
                fillOpacity = 0.8,
                bringToFront = T
              ),
              popup = paste0("GEOID: ", mapblkgps$GEOID, "<br>",
                             "Max available <br> advertised download speeds: ", round(mapblkgps$bbmax_dl, 2))
  ) %>% 
  addLegend("bottomright", pal = pal, values = mapblkgps$bbmax_dl, 
            title = "Max available <br>advertised <br> download speeds", opacity = 0.7)

Blocks

Block level maps are slow to render and may be added later.